1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25 package xmlkit;
26
27 import java.util.*;
28 import java.util.jar.*;
29 import java.lang.reflect.*;
30 import java.io.*;
31 import xmlkit.XMLKit.Element;
32
33
34
35
36 public class ClassReader extends ClassSyntax {
37
38 private static final CommandLineParser CLP = new CommandLineParser(""
39 + "-source: +> = \n"
40 + "-dest: +> = \n"
41 + "-encoding: +> = \n"
42 + "-jcov $ \n -nojcov !-jcov \n"
43 + "-verbose $ \n -noverbose !-verbose \n"
44 + "-pretty $ \n -nopretty !-pretty \n"
45 + "-keepPath $ \n -nokeepPath !-keepPath \n"
46 + "-keepCP $ \n -nokeepCP !-keepCP \n"
47 + "-keepBytes $ \n -nokeepBytes !-keepBytes \n"
48 + "-parseBytes $ \n -noparseBytes !-parseBytes \n"
49 + "-resolveRefs $ \n -noresolveRefs !-resolveRefs \n"
50 + "-keepOrder $ \n -nokeepOrder !-keepOrder \n"
51 + "-keepSizes $ \n -nokeepSizes !-keepSizes \n"
52 + "-continue $ \n -nocontinue !-continue \n"
53 + "-attrDef & \n"
54 + "-@ >-@ . \n"
55 + "- +? \n"
56 + "\n");
57
58 public static void main(String[] ava) throws IOException {
59 ArrayList<String> av = new ArrayList<String>(Arrays.asList(ava));
60 HashMap<String, String> props = new HashMap<String, String>();
61 props.put("-encoding:", "UTF8");
62 props.put("-keepOrder", null);
63 props.put("-pretty", "1");
64 props.put("-continue", "1");
65 CLP.parse(av, props);
66
67 File source = asFile(props.get("-source:"));
68 File dest = asFile(props.get("-dest:"));
69 String encoding = props.get("-encoding:");
70 boolean contError = props.containsKey("-continue");
71 ClassReader options = new ClassReader();
72 options.copyOptionsFrom(props);
73
74
75
76
77
78
79
80
81
82 if (av.isEmpty()) {
83 av.add("doit");
84 }
85 boolean readList = false;
86 for (String a : av) {
87 if (readList) {
88 readList = false;
89 InputStream fin;
90 if (a.equals("-")) {
91 fin = System.in;
92 } else {
93 fin = new FileInputStream(a);
94 }
95
96 BufferedReader files = makeReader(fin, encoding);
97 for (String file; (file = files.readLine()) != null;) {
98 doFile(file, source, dest, options, encoding, contError);
99 }
100 if (fin != System.in) {
101 fin.close();
102 }
103 } else if (a.equals("-@")) {
104 readList = true;
105 } else if (a.startsWith("-")) {
106 throw new RuntimeException("Bad flag argument: " + a);
107 } else if (source.getName().endsWith(".jar")) {
108 doJar(a, source, dest, options, encoding, contError);
109 } else {
110 doFile(a, source, dest, options, encoding, contError);
111 }
112 }
113 }
114
115 private static File asFile(String str) {
116 return (str == null) ? null : new File(str);
117 }
118
119 private static void doFile(String a,
120 File source, File dest,
121 ClassReader options, String encoding,
122 boolean contError) throws IOException {
123 if (!contError) {
124 doFile(a, source, dest, options, encoding);
125 } else {
126 try {
127 doFile(a, source, dest, options, encoding);
128 } catch (Exception ee) {
129 System.out.println("Error processing " + source + ": " + ee);
130 }
131 }
132 }
133
134 private static void doJar(String a, File source, File dest, ClassReader options,
135 String encoding, Boolean contError) throws IOException {
136 try {
137 JarFile jf = new JarFile(source);
138 for (JarEntry je : Collections.list((Enumeration<JarEntry>) jf.entries())) {
139 String name = je.getName();
140 if (!name.endsWith(".class")) {
141 continue;
142 }
143 doStream(name, jf.getInputStream(je), dest, options, encoding);
144 }
145 } catch (IOException ioe) {
146 if (contError) {
147 System.out.println("Error processing " + source + ": " + ioe);
148 } else {
149 throw ioe;
150 }
151 }
152 }
153
154 private static void doStream(String a, InputStream in, File dest,
155 ClassReader options, String encoding) throws IOException {
156
157 File f = new File(a);
158 ClassReader cr = new ClassReader(options);
159 Element e = cr.readFrom(in);
160
161 OutputStream out;
162 if (dest == null) {
163
164 out = System.out;
165 } else {
166 File outf = new File(dest, f.isAbsolute() ? f.getName() : f.getPath());
167 String outName = outf.getName();
168 File outSubdir = outf.getParentFile();
169 outSubdir.mkdirs();
170 int extPos = outName.lastIndexOf('.');
171 if (extPos > 0) {
172 outf = new File(outSubdir, outName.substring(0, extPos) + ".xml");
173 }
174 out = new FileOutputStream(outf);
175 }
176
177 Writer outw = makeWriter(out, encoding);
178 if (options.pretty || !options.keepOrder) {
179 e.writePrettyTo(outw);
180 } else {
181 e.writeTo(outw);
182 }
183 if (out == System.out) {
184 outw.write("\n");
185 outw.flush();
186 } else {
187 outw.close();
188 }
189 }
190
191 private static void doFile(String a,
192 File source, File dest,
193 ClassReader options, String encoding) throws IOException {
194 File inf = new File(source, a);
195 if (dest != null && options.verbose) {
196 System.out.println("Reading " + inf);
197 }
198
199 BufferedInputStream in = new BufferedInputStream(new FileInputStream(inf));
200
201 doStream(a, in, dest, options, encoding);
202
203 }
204
205 public static BufferedReader makeReader(InputStream in, String encoding) throws IOException {
206
207 if (encoding.equals("8BIT")) {
208 encoding = EIGHT_BIT_CHAR_ENCODING;
209 }
210 if (encoding.equals("UTF8")) {
211 encoding = UTF8_ENCODING;
212 }
213 if (encoding.equals("DEFAULT")) {
214 encoding = null;
215 }
216 if (encoding.equals("-")) {
217 encoding = null;
218 }
219 Reader inw;
220 in = new BufferedInputStream(in);
221 if (encoding == null) {
222 inw = new InputStreamReader(in);
223 } else {
224 inw = new InputStreamReader(in, encoding);
225 }
226 return new BufferedReader(inw);
227 }
228
229 public static Writer makeWriter(OutputStream out, String encoding) throws IOException {
230
231 if (encoding.equals("8BIT")) {
232 encoding = EIGHT_BIT_CHAR_ENCODING;
233 }
234 if (encoding.equals("UTF8")) {
235 encoding = UTF8_ENCODING;
236 }
237 if (encoding.equals("DEFAULT")) {
238 encoding = null;
239 }
240 if (encoding.equals("-")) {
241 encoding = null;
242 }
243 Writer outw;
244 if (encoding == null) {
245 outw = new OutputStreamWriter(out);
246 } else {
247 outw = new OutputStreamWriter(out, encoding);
248 }
249 return new BufferedWriter(outw);
250 }
251
252 public Element result() {
253 return cfile;
254 }
255 protected InputStream in;
256 protected ByteArrayOutputStream buf = new ByteArrayOutputStream(1024);
257 protected byte cpTag[];
258 protected String cpName[];
259 protected String[] callables;
260 public static final String REF_PREFIX = "#";
261
262 public boolean pretty = false;
263 public boolean verbose = false;
264 public boolean keepPath = false;
265 public boolean keepCP = false;
266 public boolean keepBytes = false;
267 public boolean parseBytes = true;
268 public boolean resolveRefs = true;
269 public boolean keepOrder = true;
270 public boolean keepSizes = false;
271
272 public ClassReader() {
273 super.cfile = new Element("ClassFile");
274 }
275
276 public ClassReader(ClassReader options) {
277 this();
278 copyOptionsFrom(options);
279 }
280
281 public void copyOptionsFrom(ClassReader options) {
282 pretty = options.pretty;
283 verbose = options.verbose;
284 keepPath = options.keepPath;
285 keepCP = options.keepCP;
286 keepBytes = options.keepBytes;
287 parseBytes = options.parseBytes;
288 resolveRefs = options.resolveRefs;
289 keepSizes = options.keepSizes;
290 keepOrder = options.keepOrder;
291 attrTypes = options.attrTypes;
292 }
293
294 public void copyOptionsFrom(Map<String, String> options) {
295 if (options.containsKey("-pretty")) {
296 pretty = (options.get("-pretty") != null);
297 }
298 if (options.containsKey("-verbose")) {
299 verbose = (options.get("-verbose") != null);
300 }
301 if (options.containsKey("-keepPath")) {
302 keepPath = (options.get("-keepPath") != null);
303 }
304 if (options.containsKey("-keepCP")) {
305 keepCP = (options.get("-keepCP") != null);
306 }
307 if (options.containsKey("-keepBytes")) {
308 keepBytes = (options.get("-keepBytes") != null);
309 }
310 if (options.containsKey("-parseBytes")) {
311 parseBytes = (options.get("-parseBytes") != null);
312 }
313 if (options.containsKey("-resolveRefs")) {
314 resolveRefs = (options.get("-resolveRefs") != null);
315 }
316 if (options.containsKey("-keepSizes")) {
317 keepSizes = (options.get("-keepSizes") != null);
318 }
319 if (options.containsKey("-keepOrder")) {
320 keepOrder = (options.get("-keepOrder") != null);
321 }
322 if (options.containsKey("-attrDef")) {
323 addAttrTypes(options.get("-attrDef").split(" "));
324 }
325 if (options.get("-jcov") != null) {
326 addJcovAttrTypes();
327 }
328 }
329
330 public Element readFrom(InputStream in) throws IOException {
331 this.in = in;
332
333 int magic = u4();
334 if (magic != 0xCAFEBABE) {
335 throw new RuntimeException("bad magic number " + Integer.toHexString(magic));
336 }
337 cfile.setAttr("magic", "" + magic);
338 int minver = u2();
339 int majver = u2();
340 cfile.setAttr("minver", "" + minver);
341 cfile.setAttr("majver", "" + majver);
342 readCP();
343 readClass();
344 return result();
345 }
346
347 public Element readFrom(File file) throws IOException {
348 InputStream in = null;
349 try {
350 in = new FileInputStream(file);
351 Element e = readFrom(new BufferedInputStream(in));
352 if (keepPath) {
353 e.setAttr("path", file.toString());
354 }
355 return e;
356 } finally {
357 if (in != null) {
358 in.close();
359 }
360 }
361 }
362
363 private void readClass() throws IOException {
364 klass = new Element("Class");
365 cfile.add(klass);
366 int flags = u2();
367 String thisk = cpRef();
368 String superk = cpRef();
369 klass.setAttr("name", thisk);
370 boolean flagsSync = ((flags & Modifier.SYNCHRONIZED) != 0);
371 flags &= ~Modifier.SYNCHRONIZED;
372 String flagString = flagString(flags, klass);
373 if (!flagsSync) {
374 if (flagString.length() > 0) {
375 flagString += " ";
376 }
377 flagString += "!synchronized";
378 }
379 klass.setAttr("flags", flagString);
380 klass.setAttr("super", superk);
381 for (int len = u2(), i = 0; i < len; i++) {
382 String interk = cpRef();
383 klass.add(new Element("Interface", "name", interk));
384 }
385 Element fields = readMembers("Field");
386 klass.addAll(fields);
387 Element methods = readMembers("Method");
388 if (!keepOrder) {
389 methods.sort();
390 }
391 klass.addAll(methods);
392 readAttributesFor(klass);
393 klass.trimToSize();
394 if (keepSizes) {
395 attachTo(cfile, formatAttrSizes());
396 }
397 if (paddingSize != 0) {
398 cfile.setAttr("padding", "" + paddingSize);
399 }
400 }
401
402 private Element readMembers(String kind) throws IOException {
403 int len = u2();
404 Element members = new Element(len);
405 for (int i = 0; i < len; i++) {
406 Element member = new Element(kind);
407 int flags = u2();
408 String name = cpRef();
409 String type = cpRef();
410 member.setAttr("name", name);
411 member.setAttr("type", type);
412 member.setAttr("flags", flagString(flags, member));
413 readAttributesFor(member);
414 member.trimToSize();
415 members.add(member);
416 }
417 return members;
418 }
419
420 protected String flagString(int flags, Element holder) {
421
422 int kind = 0;
423 if (holder.getName() == "Field") {
424 kind = 1;
425 }
426 if (holder.getName() == "Method") {
427 kind = 2;
428 }
429 StringBuffer sb = new StringBuffer();
430 for (int i = 0; flags != 0; i++, flags >>>= 1) {
431 if ((flags & 1) != 0) {
432 if (sb.length() > 0) {
433 sb.append(' ');
434 }
435 if (i < modifierNames.length) {
436 String[] names = modifierNames[i];
437 String name = (kind < names.length) ? names[kind] : null;
438 for (String name2 : names) {
439 if (name != null) {
440 break;
441 }
442 name = name2;
443 }
444 sb.append(name);
445 } else {
446 sb.append("#").append(1 << i);
447 }
448 }
449 }
450 return sb.toString();
451 }
452
453 private void readAttributesFor(Element x) throws IOException {
454 Element prevCurrent;
455 Element y = new Element();
456 if (x.getName() == "Code") {
457 prevCurrent = currentCode;
458 currentCode = x;
459 } else {
460 prevCurrent = currentMember;
461 currentMember = x;
462 }
463 for (int len = u2(), i = 0; i < len; i++) {
464 int ref = u2();
465 String uname = cpName(ref).intern();
466 String refName = uname;
467 if (!resolveRefs) {
468 refName = (REF_PREFIX + ref).intern();
469 }
470 String qname = (x.getName() + "." + uname).intern();
471 String wname = ("*." + uname).intern();
472 String type = attrTypes.get(qname);
473 if (type == null || "".equals(type)) {
474 type = attrTypes.get(wname);
475 }
476 if ("".equals(type)) {
477 type = null;
478 }
479 int size = u4();
480 int[] countVar = attrSizes.get(qname);
481 if (countVar == null) {
482 attrSizes.put(qname, countVar = new int[2]);
483 }
484 countVar[0] += 1;
485 countVar[1] += size;
486 buf.reset();
487 for (int j = 0; j < size; j++) {
488 buf.write(u1());
489 }
490 if (type == null && size == 0) {
491 y.add(new Element(uname));
492 } else if (type == null) {
493
494
495 Element a = new Element("Attribute",
496 new String[]{"Name", refName},
497 buf.toString(EIGHT_BIT_CHAR_ENCODING));
498 a.addContent(getCPDigest());
499 y.add(a);
500 } else if (type.equals("")) {
501
502 } else {
503 InputStream in0 = in;
504 int fileSize0 = fileSize;
505 ByteArrayInputStream in1 = new ByteArrayInputStream(buf.toByteArray());
506 boolean ok = false;
507 try {
508 in = in1;
509
510 Element aval;
511 if (type.equals("<Code>...")) {
512
513 aval = readCode();
514 } else if (type.equals("<Frame>...")) {
515
516 aval = readStackMap(false);
517 } else if (type.equals("<FrameX>...")) {
518
519 aval = readStackMap(true);
520 } else if (type.startsWith("[")) {
521 aval = readAttributeCallables(type);
522 } else {
523 aval = readAttribute(type);
524 }
525
526 attachTo(y, aval);
527 if (false
528 && in1.available() != 0) {
529 throw new RuntimeException("extra bytes in " + qname + " :" + in1.available());
530 }
531 ok = true;
532 } finally {
533 in = in0;
534 fileSize = fileSize0;
535 if (!ok) {
536 System.out.println("*** Failed to read " + type);
537 }
538 }
539 }
540 }
541 if (x.getName() == "Code") {
542 currentCode = prevCurrent;
543 } else {
544 currentMember = prevCurrent;
545 }
546 if (!keepOrder) {
547 y.sort();
548 y.sortAttrs();
549 }
550
551 attachTo(x, y);
552 }
553 private int fileSize = 0;
554 private int paddingSize = 0;
555 private HashMap<String, int[]> attrSizes = new HashMap<String, int[]>();
556
557 private Element formatAttrSizes() {
558 Element e = new Element("Sizes");
559 e.setAttr("fileSize", "" + fileSize);
560 for (Map.Entry<String, int[]> ie : attrSizes.entrySet()) {
561 int[] countVar = ie.getValue();
562 e.add(new Element("AttrSize",
563 "name", ie.getKey().toString(),
564 "count", "" + countVar[0],
565 "size", "" + countVar[1]));
566 }
567 return e;
568 }
569
570 private void attachTo(Element x, Object aval0) {
571 if (aval0 == null) {
572 return;
573 }
574
575 if (!(aval0 instanceof Element)) {
576 x.add(aval0);
577 return;
578 }
579 Element aval = (Element) aval0;
580 if (!aval.isAnonymous()) {
581 x.add(aval);
582 return;
583 }
584 for (int imax = aval.attrSize(), i = 0; i < imax; i++) {
585
586 attachAttrTo(x, aval.getAttrName(i), aval.getAttr(i));
587 }
588 x.addAll(aval);
589 }
590
591 private void attachAttrTo(Element x, String aname, String aval) {
592
593 String aval0 = x.getAttr(aname);
594 if (aval0 != null) {
595 aval = aval0 + " " + aval;
596 }
597 x.setAttr(aname, aval);
598 }
599
600 private Element readAttributeCallables(String type) throws IOException {
601 assert (callables == null);
602 callables = getBodies(type);
603 Element res = readAttribute(callables[0]);
604 callables = null;
605 return res;
606 }
607
608 private Element readAttribute(String type) throws IOException {
609
610 Element aval = new Element();
611 String nextAttrName = null;
612 for (int len = type.length(), next, i = 0; i < len; i = next) {
613 String value;
614 switch (type.charAt(i)) {
615 case '<':
616 assert (nextAttrName == null);
617 next = type.indexOf('>', ++i);
618 String form = type.substring(i, next++);
619 if (form.indexOf('=') < 0) {
620
621 assert (aval.attrSize() == 0);
622 assert (aval.isAnonymous());
623 aval.setName(form.intern());
624 } else {
625
626 int eqPos = form.indexOf('=');
627 nextAttrName = form.substring(0, eqPos).intern();
628 if (eqPos != form.length() - 1) {
629 value = form.substring(eqPos + 1);
630 attachAttrTo(aval, nextAttrName, value);
631 nextAttrName = null;
632 }
633
634
635 }
636 continue;
637 case '(':
638 next = type.indexOf(')', ++i);
639 int callee = Integer.parseInt(type.substring(i, next++));
640 attachTo(aval, readAttribute(callables[callee]));
641 continue;
642 case 'N':
643 {
644 int count = getInt(type.charAt(i + 1), false);
645 assert (count >= 0);
646 next = i + 2;
647 String type1 = getBody(type, next);
648 next += type1.length() + 2;
649 for (int j = 0; j < count; j++) {
650 attachTo(aval, readAttribute(type1));
651 }
652 }
653 continue;
654 case 'T':
655 int tagValue;
656 if (type.charAt(++i) == 'S') {
657 tagValue = getInt(type.charAt(++i), true);
658 } else {
659 tagValue = getInt(type.charAt(i), false);
660 }
661 attachAttrTo(aval, "tag", "" + tagValue);
662 ++i;
663
664
665 for (boolean foundCase = false;; i = next) {
666 assert (type.charAt(i) == '(');
667 next = type.indexOf(')', ++i);
668 assert (next >= i);
669 if (type.charAt(next - 1) == '\\'
670 && type.charAt(next - 2) != '\\')
671 {
672 next = type.indexOf(')', next + 1);
673 }
674 String caseStr = type.substring(i, next++);
675 String type1 = getBody(type, next);
676 next += type1.length() + 2;
677 boolean lastCase = (caseStr.length() == 0);
678 if (!foundCase
679 && (lastCase || matchTag(tagValue, caseStr))) {
680 foundCase = true;
681
682 attachTo(aval, readAttribute(type1));
683 }
684 if (lastCase) {
685 break;
686 }
687 }
688 continue;
689 case 'B':
690 case 'H':
691 case 'I':
692 next = i + 1;
693 value = "" + getInt(type.charAt(i), false);
694 break;
695 case 'K':
696 assert ("IJFDLQ".indexOf(type.charAt(i + 1)) >= 0);
697 assert (type.charAt(i + 2) == 'H');
698 next = i + 3;
699 value = cpRef();
700 break;
701 case 'R':
702 assert ("CSDFMIU?".indexOf(type.charAt(i + 1)) >= 0);
703 assert (type.charAt(i + 2) == 'H');
704 next = i + 3;
705 value = cpRef();
706 break;
707 case 'P':
708 next = i + 2;
709 value = "" + getInt(type.charAt(i + 1), false);
710 break;
711 case 'S':
712 next = i + 2;
713 value = "" + getInt(type.charAt(i + 1), true);
714 break;
715 case 'F':
716 next = i + 2;
717 value = flagString(getInt(type.charAt(i + 1), false), currentMember);
718 break;
719 default:
720 throw new RuntimeException("bad attr format '" + type.charAt(i) + "': " + type);
721 }
722
723 if (nextAttrName != null) {
724 attachAttrTo(aval, nextAttrName, value);
725 nextAttrName = null;
726 } else {
727 attachTo(aval, value);
728 }
729 }
730
731 assert (nextAttrName == null);
732 return aval;
733 }
734
735 private int getInt(char ch, boolean signed) throws IOException {
736 if (signed) {
737 switch (ch) {
738 case 'B':
739 return (byte) u1();
740 case 'H':
741 return (short) u2();
742 case 'I':
743 return (int) u4();
744 }
745 } else {
746 switch (ch) {
747 case 'B':
748 return u1();
749 case 'H':
750 return u2();
751 case 'I':
752 return u4();
753 }
754 }
755 assert ("BHIJ".indexOf(ch) >= 0);
756 return 0;
757 }
758
759 private Element readCode() throws IOException {
760 int stack = u2();
761 int local = u2();
762 int length = u4();
763 StringBuilder sb = new StringBuilder(length);
764 for (int i = 0; i < length; i++) {
765 sb.append((char) u1());
766 }
767 String bytecodes = sb.toString();
768 Element e = new Element("Code",
769 "stack", "" + stack,
770 "local", "" + local);
771 Element bytes = new Element("Bytes", (String[]) null, bytecodes);
772 if (keepBytes) {
773 e.add(bytes);
774 }
775 if (parseBytes) {
776 e.add(parseByteCodes(bytecodes));
777 }
778 for (int len = u2(), i = 0; i < len; i++) {
779 int start = u2();
780 int end = u2();
781 int catsh = u2();
782 String clasz = cpRef();
783 e.add(new Element("Handler",
784 "start", "" + start,
785 "end", "" + end,
786 "catch", "" + catsh,
787 "class", clasz));
788 }
789 readAttributesFor(e);
790 e.trimToSize();
791 return e;
792 }
793
794 private Element parseByteCodes(String bytecodes) {
795 Element e = InstructionSyntax.parse(bytecodes);
796 for (Element ins : e.elements()) {
797 Number ref = ins.getAttrNumber("ref");
798 if (ref != null && resolveRefs) {
799 int id = ref.intValue();
800 String val = cpName(id);
801 if (ins.getName().startsWith("ldc")) {
802
803 ins.add(val);
804 val = "";
805 byte tag = (id >= 0 && id < cpTag.length) ? cpTag[id] : 0;
806 if (tag != 0) {
807 ins.setAttrLong("tag", tag);
808 }
809 }
810 if (ins.getName() == "invokeinterface"
811 && computeInterfaceNum(val) == ins.getAttrLong("num")) {
812 ins.setAttr("num", null);
813 }
814 ins.setAttr("ref", null);
815 ins.setAttr("val", val);
816 }
817 }
818 return e;
819 }
820
821 private Element readStackMap(boolean hasXOption) throws IOException {
822 Element result = new Element();
823 Element bytes = currentCode.findElement("Bytes");
824 assert (bytes != null && bytes.size() == 1);
825 int byteLength = ((String) bytes.get(0)).length();
826 boolean uoffsetIsU4 = (byteLength >= (1 << 16));
827 boolean ulocalvarIsU4 = currentCode.getAttrLong("local") >= (1 << 16);
828 boolean ustackIsU4 = currentCode.getAttrLong("stack") >= (1 << 16);
829 if (hasXOption || uoffsetIsU4 || ulocalvarIsU4 || ustackIsU4) {
830 Element flags = new Element("StackMapFlags");
831 if (hasXOption) {
832 flags.setAttr("hasXOption", "true");
833 }
834 if (uoffsetIsU4) {
835 flags.setAttr("uoffsetIsU4", "true");
836 }
837 if (ulocalvarIsU4) {
838 flags.setAttr("ulocalvarIsU4", "true");
839 }
840 if (ustackIsU4) {
841 flags.setAttr("ustackIsU4", "true");
842 }
843 currentCode.add(flags);
844 }
845 int frame_count = (uoffsetIsU4 ? u4() : u2());
846 for (int i = 0; i < frame_count; i++) {
847 int bci = (uoffsetIsU4 ? u4() : u2());
848 int flags = (hasXOption ? u1() : 0);
849 Element frame = new Element("Frame");
850 result.add(frame);
851 if (flags != 0) {
852 frame.setAttr("flags", "" + flags);
853 }
854 frame.setAttr("bci", "" + bci);
855
856 final int LOCALS = 0, STACK = 1;
857 for (int j = LOCALS; j <= STACK; j++) {
858 int typeSize;
859 if (j == LOCALS) {
860 typeSize = (ulocalvarIsU4 ? u4() : u2());
861 } else {
862 typeSize = (ustackIsU4 ? u4() : u2());
863 }
864 Element types = new Element(j == LOCALS ? "Local" : "Stack");
865 for (int k = 0; k < typeSize; k++) {
866 int tag = u1();
867 Element type = new Element(itemTagName(tag));
868 types.add(type);
869 switch (tag) {
870 case ITEM_Object:
871 type.setAttr("class", cpRef());
872 break;
873 case ITEM_Uninitialized:
874 case ITEM_ReturnAddress:
875 type.setAttr("bci", "" + (uoffsetIsU4 ? u4() : u2()));
876 break;
877 }
878 }
879 if (types.size() > 0) {
880 frame.add(types);
881 }
882 }
883 }
884 return result;
885 }
886
887 private void readCP() throws IOException {
888 int cpLen = u2();
889 cpTag = new byte[cpLen];
890 cpName = new String[cpLen];
891 int cpTem[][] = new int[cpLen][];
892 for (int i = 1; i < cpLen; i++) {
893 cpTag[i] = (byte) u1();
894 switch (cpTag[i]) {
895 case CONSTANT_Utf8:
896 buf.reset();
897 for (int len = u2(), j = 0; j < len; j++) {
898 buf.write(u1());
899 }
900 cpName[i] = buf.toString(UTF8_ENCODING);
901 break;
902 case CONSTANT_Integer:
903 cpName[i] = String.valueOf((int) u4());
904 break;
905 case CONSTANT_Float:
906 cpName[i] = String.valueOf(Float.intBitsToFloat(u4()));
907 break;
908 case CONSTANT_Long:
909 cpName[i] = String.valueOf(u8());
910 i += 1;
911 break;
912 case CONSTANT_Double:
913 cpName[i] = String.valueOf(Double.longBitsToDouble(u8()));
914 i += 1;
915 break;
916 case CONSTANT_Class:
917 case CONSTANT_String:
918 cpTem[i] = new int[]{u2()};
919 break;
920 case CONSTANT_Fieldref:
921 case CONSTANT_Methodref:
922 case CONSTANT_InterfaceMethodref:
923 case CONSTANT_NameAndType:
924 cpTem[i] = new int[]{u2(), u2()};
925 break;
926 }
927 }
928 for (int i = 1; i < cpLen; i++) {
929 switch (cpTag[i]) {
930 case CONSTANT_Class:
931 case CONSTANT_String:
932 cpName[i] = cpName[cpTem[i][0]];
933 break;
934 case CONSTANT_NameAndType:
935 cpName[i] = cpName[cpTem[i][0]] + " " + cpName[cpTem[i][1]];
936 break;
937 }
938 }
939
940 for (int i = 1; i < cpLen; i++) {
941 switch (cpTag[i]) {
942 case CONSTANT_Fieldref:
943 case CONSTANT_Methodref:
944 case CONSTANT_InterfaceMethodref:
945 cpName[i] = cpName[cpTem[i][0]] + " " + cpName[cpTem[i][1]];
946 break;
947 }
948 }
949 cpool = new Element("ConstantPool", cpName.length);
950 for (int i = 0; i < cpName.length; i++) {
951 if (cpName[i] == null) {
952 continue;
953 }
954 cpool.add(new Element(cpTagName(cpTag[i]),
955 new String[]{"id", "" + i},
956 cpName[i]));
957 }
958 if (keepCP) {
959 cfile.add(cpool);
960 }
961 }
962
963 private String cpRef() throws IOException {
964 int ref = u2();
965 if (resolveRefs) {
966 return cpName(ref);
967 } else {
968 return REF_PREFIX + ref;
969 }
970 }
971
972 private String cpName(int id) {
973 if (id >= 0 && id < cpName.length) {
974 return cpName[id];
975 } else {
976 return "[CP#" + Integer.toHexString(id) + "]";
977 }
978 }
979
980 private long u8() throws IOException {
981 return ((long) u4() << 32) + (((long) u4() << 32) >>> 32);
982 }
983
984 private int u4() throws IOException {
985 return (u2() << 16) + u2();
986 }
987
988 private int u2() throws IOException {
989 return (u1() << 8) + u1();
990 }
991
992 private int u1() throws IOException {
993 int x = in.read();
994 if (x < 0) {
995 paddingSize++;
996 return 0;
997 }
998 fileSize++;
999 assert (x == (x & 0xFF));
1000 return x;
1001 }
1002 }
1003